package com.itcast.springboot.realm;

import com.itcast.springboot.waste_recovery.domain.User;
import com.itcast.springboot.waste_recovery.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;

/**
 * @Author 郭泽鹏
 * @Date 2020/8/18 11:40
 * @Version 1.0
 * @Description 自定义realm域：用户登录时的自定义认证和授权方法
 */
@Slf4j
public class CustomRealm extends AuthorizingRealm {

    @Resource
    UserService userService;

    /**
     * 设置realm域名称
     * @param name realm域名称
     */
    @Override
    public void setName(String name) {
        super.setName("CustomRealm");
    }

    /**
     * 授权方法
     *      操作的时候，判断用户是否具有相应的权限
     *          先认证 -- 安全数据
     *          再授权 -- 根据安全数据获取用户具有的所有操作权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("--->执行了授权方法");

        //1.获取已认证的用户数据
        User user = (User) principalCollection.getPrimaryPrincipal();   //得到唯一的安全数据

        //2.根据用户数据获取用户的权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Map<String, Object> map = userService.getRolesAndPermissionByUserId(user.getId());
        Set<String> roleNames = (Set<String>) map.get("roleNames");
        Set<String> permTypes = (Set<String>) map.get("permTypes");
        info.setStringPermissions(permTypes);
        info.setRoles(roleNames);
        return info;
    }

    /**
     * 认证方法
     * @param authenticationToken 封装传递的用户名和密码
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("--->执行了认证方法");
        //1.获取登录的账户和密码
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userPhone = token.getUsername();
        String password = new String(token.getPassword());
        log.info("--->database password：" + password);
        //2.根据用户名查询数据库
        User user = userService.findByPhoneOrEmail(userPhone);
        //3.判断用户是否存在或者密码是否一致
        if (user != null && user.getUserPassword().equals(password)){
            //4.如果一致返回安全数据
            //参数：安全数据，密码，realm域名
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserPassword(), this.getName());
            return info;
        }
        //5.不一致，返回null（抛出异常）
        return null;
    }
}